package algorithm;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import entity.TwoTuple;
import problem.Problem;
import solution.Solution;

/**
 * 表示一个算法
 * 
 * @author Administrator
 * @param T1和T2指定Problem和Solution中的数值类型
 * @param S指定解的类型
 *
 */
public abstract class Algorithm<T extends Number, T2 extends Number, S extends Solution<T,T2>, Tuple> {

	/* 所有算法都会有的参数 */
	Problem<T, Tuple, T2> Mproblem;// 需要解决的问题
	// 让具体的问题和具体的算法相关联

	protected Random random = new Random();// 随机对象，用于产生随机数

	protected final boolean isMax;

	protected final String algName;// 算法名

	protected S best;// 全局最优解

	protected S worst;// 最差解

	protected List<S> population;// 种群

	protected int popSize;// 种群大小

	int current_NFE = 0;// 当前函数评估次数

	protected final int NFE;// 最大迭代次数

	protected double timeTaken;// 运行花费的时间

	protected final List<TwoTuple<Integer, S>> records = new ArrayList<TwoTuple<Integer, S>>();// 用于记录current_NFE和best

	public Algorithm(Problem<T, Tuple, T2> problem, boolean isMax, String algName, int popSize, int NFE) {
		this.Mproblem = problem;
		this.isMax = isMax;
		this.algName = algName;
		this.population = new ArrayList<S>();
		this.popSize = popSize;
		this.NFE = NFE;
	}

	/** 所有算法都可以使用的操作 **/
	public Problem<T, Tuple, T2> getProblem() {
		return Mproblem;
	}

	public void setProblem(Problem<T, Tuple, T2> problem) {
		this.Mproblem = problem;
	}

	public Random getRandom() {
		return random;
	}

	public void setRandom(Random random) {
		this.random = random;
	}

	public Problem<T, Tuple, T2> getMproblem() {
		return Mproblem;
	}

	public void setMproblem(Problem<T, Tuple, T2> mproblem) {
		Mproblem = mproblem;
	}

	public int getCurrent_NFE() {
		return current_NFE;
	}

	public void setCurrent_NFE(int current_NFE) {
		this.current_NFE = current_NFE;
	}

	public List<S> getPopulation() {
		return population;
	}

	public void setBest(S best) {
		this.best = best;
	}

	public void setPopulation(List<S> population) {
		this.population = population;
	}

	public int getPopSize() {
		return popSize;
	}

	public void setPopSize(int popSize) {
		this.popSize = popSize;
	}

	public int getCurrent_iterations() {
		return current_NFE;
	}

	public void setCurrent_iterations(int current_iterations) {
		this.current_NFE = current_iterations;
	}

	public int getNFE() {
		return NFE;
	}

	public double getTimeTaken() {
		return timeTaken;
	}

	public void setTimeTaken(double timeTaken) {
		this.timeTaken = timeTaken;
	}

	public boolean isMax() {
		return isMax;
	}

	public String getAlgName() {
		return algName;
	}

	public List<TwoTuple<Integer, S>> getRecords() {
		return records;
	}

	/**
	 * 表示运行算法
	 * 
	 * @return 最优解和算法运行时间
	 */
	public TwoTuple<S, Double> run() {
		long startTime = System.currentTimeMillis();
		// 初始化种群
		initialize();
		// 评估种群
		evaluate();
		// 在NFE未达到最大NFE之前，都需要执行进化
		for (; current_NFE < NFE;) {
			// System.out.println("current NFE:" + current_NFE);
			evolve();
			// 每迭代一次，更新相关参数
			updateParameters();
		}
		long endTime = System.currentTimeMillis();
		timeTaken = (double) (endTime - startTime) / 1000;
		return new TwoTuple<S, Double>(best, timeTaken);
	}

	/**
	 * 初始化一组种群
	 */
	public abstract void initialize();// 初始化一组种群

	/**
	 * 对种群做出评估，计算每个解的函数适应度以及得到最优解和最差解
	 */
	protected abstract void evaluate();

	/**
	 * 更新参数，[可选]
	 */
	public abstract void updateParameters();// 更新参数，[可选]

	/**
	 * 比较两个解的大小 solution1优于solution2,return 1; solution1等于solution2,return
	 * 0;solution1低于solution2,return -1
	 * 
	 * @param solution1
	 * @param solution2
	 * @return
	 */
	protected int compare(Solution<T, T2> solution1, Solution<T, T2> solution2) {
		double value1 = solution1.getValue().doubleValue(), value2 = solution2.getValue().doubleValue();
		if (value1 > value2) {
			return isMax == true ? 1 : -1;
		} else if (value1 == value2) {
			return 0;
		} else {
			return isMax == true ? -1 : 1;
		}
	}

	/**
	 * 得到当前种群中的最优解
	 */
	public S getBestSolution() {
		return best;
	}

	/**
	 * 得到当前种群中的最差解
	 */
	public S getWorstSolution() {
		return worst;
	}

	/**
	 * 一次迭代
	 */
	public abstract void evolve();// 迭代


}
